#include <stdio.h>
#include <string.h>
#include <string>

#include "cLua.h"
#include "../lua_rover/lua_rover.hpp"

#pragma warning(disable:4996)

extern "C" {
	#include "../lua_5_1_3/lua.h"
	#include "../lua_5_1_3/lualib.h"
	#include "../lua_5_1_3/lauxlib.h"
};

#pragma warning(default:4996)

#include <iostream>

namespace umtl
{
	//////////////////////////////////////////////////////////////////////////
	// 

	void DefaultErrorHandler( char const * msg )
	{
		std::cout << msg << std::endl;
	}

	cLua::cLua()
	{
		m_pErrorHandler = &DefaultErrorHandler;
		global_state_ = 0;

		/*
		m_pScriptContext = lua_open();
		luaopen_base(m_pScriptContext);
		//luaopen_io(m_pScriptContext);
		luaopen_string(m_pScriptContext);
		luaopen_math(m_pScriptContext);
		luaopen_debug(m_pScriptContext);
		luaopen_table(m_pScriptContext);
		*/
	}

	cLua::~cLua()
	{
		/*
		if(m_pScriptContext)
			lua_close(m_pScriptContext);
			*/
		lua_States::iterator iter = lua_states_.begin();
		for(; iter!=lua_states_.end(); ++iter)
		{
			if( iter->second )
			{
				delete iter->second;
			}
		}

		if( global_state_ )
			delete global_state_;
	}

	/*
	static std::string findScript(const char *pFname)
	{
		FILE *fTest;

		char drive[_MAX_DRIVE];
		char dir[_MAX_DIR];
		char fname[_MAX_FNAME];
		char ext[_MAX_EXT];

		_splitpath_s( pFname, drive, _MAX_DRIVE, dir, _MAX_DIR, fname, _MAX_FNAME, ext, _MAX_EXT );

		std::string strTestFile = (std::string) drive + dir + "Scripts\\" + fname + ".LUB";
		fopen_s(&fTest, strTestFile.c_str(), "r");
		if(fTest == NULL)
		{
			//not that one...
			strTestFile = (std::string) drive + dir + "Scripts\\" + fname + ".LUA";
			fopen_s(&fTest, strTestFile.c_str(), "r");
		}

		if(fTest == NULL)
		{
			//not that one...
			strTestFile = (std::string) drive + dir + fname + ".LUB";
			fopen_s(&fTest, strTestFile.c_str(), "r");
		}

		if(fTest == NULL)
		{
			//not that one...
			//not that one...
			strTestFile = (std::string) drive + dir + fname + ".LUA";
			fopen_s(&fTest, strTestFile.c_str(), "r");
		}

		if(fTest != NULL)
		{
			fclose(fTest);
		}

		return strTestFile;
	}
	*/



	bool cLua::RunScriptOnly(const char *pFname)
	{
		//std::string strFilename = findScript(pFname);
		//const char *pFilename = strFilename.c_str();

		lua_State * script_context = GetScriptContext(pFname);

		return RunScript( pFname, script_context );
	}

	bool cLua::RunScript(const char *pFname, lua_State * context)
	{
		lua_State * script_context = GetScriptContext(0);
		
		if( context )
			script_context = context;
		//else
		//	FindLuaGlobal(0)->SetFileName( pFname );

		if (0 != luaL_loadfile(script_context, pFname))
		{
			if(m_pErrorHandler)
			{
				char buf[256];
				sprintf_s(buf, sizeof(buf), "Lua Error - Script Load\nScript Name:%s\nError Message:%s\n", pFname, luaL_checkstring(script_context, -1));
				m_pErrorHandler(buf);
			}

			return false;
		}
		if (0 != lua_pcall(script_context, 0, LUA_MULTRET, 0))
		{
			if(m_pErrorHandler)
			{
				char buf[256];
				sprintf_s(buf, sizeof(buf), "Lua Error - Script Run\nScript Name:%s\nError Message:%s\n", pFname, luaL_checkstring(script_context, -1));
				m_pErrorHandler(buf);
			}

			return false;
		}
		return true;

	}

	bool cLua::RunString(const char *pCommand)
	{
		lua_State * lua_state = GetScriptContext(0);

		if (0 != luaL_loadbuffer(lua_state, pCommand, strlen(pCommand), NULL))
		{
			if(m_pErrorHandler)
			{
				char buf[256];
				sprintf_s(buf, sizeof(buf), "Lua Error - String Load\nString:%s\nError Message:%s\n", pCommand, luaL_checkstring(lua_state, -1));
				m_pErrorHandler(buf);
			}

			return false;
		}
		if (0 != lua_pcall(lua_state, 0, LUA_MULTRET, 0))
		{
			if(m_pErrorHandler)
			{
				char buf[256];
				sprintf_s(buf, sizeof(buf), "Lua Error - String Run\nString:%s\nError Message:%s\n", pCommand, luaL_checkstring(lua_state, -1));
				m_pErrorHandler(buf);
			}

			return false;
		}
		return true;
	}

	const char *cLua::GetErrorString(const char* name)
	{
		lua_State * lua_state = GetScriptContext(name);
		return luaL_checkstring(lua_state, -1);
	}

	bool cLua::AddFunction(const char *lua_name, const char *pFunctionName, LuaFunctionType pFunction)
	{
		lua_State * lua_state = GetScriptContext(lua_name);
		lua_register(lua_state, pFunctionName, pFunction);
		return true;
	}

	const char *cLua::GetStringArgument(const char *lua_name, int num, const char *pDefault)
	{
		lua_State * lua_state = GetScriptContext(lua_name);
		return luaL_optstring(lua_state, num, pDefault);
	}

	double cLua::GetNumberArgument(const char *lua_name, int num, double dDefault)
	{
		lua_State * lua_state = GetScriptContext(lua_name);
		return luaL_optnumber(lua_state, num, dDefault);
	}

	void cLua::PushString(const char *lua_name, const char *pString)
	{
		lua_State * lua_state = GetScriptContext(lua_name);
		lua_pushstring(lua_state, pString);
	}

	void cLua::PushNumber(const char *lua_name, double value)
	{
		lua_State * lua_state = GetScriptContext(lua_name);
		lua_pushnumber(lua_state, value);
	}

	lua_State * cLua::GetScriptContext(const char* lua_name)
	{
		LuaRover::LuaGlobal * lua_global = FindLuaGlobal(lua_name);

		return lua_global->GetLuaState();
	}

	LuaRover::LuaGlobal * cLua::FindLuaGlobal(const char* lua_name)
	{
		LuaRover::LuaGlobal * lua_global = NULL;

		if( lua_name == 0 )
		{
			if( !global_state_ )
				global_state_ = new LuaRover::LuaGlobal(lua_name);

			lua_global = global_state_;
		}
		else
		{
			//std::string strFilename = findScript(lua_name);
			//const char *pFilename = strFilename.c_str();

			lua_States::iterator iter = lua_states_.find(lua_name);
			if( iter == lua_states_.end() )
			{
				lua_global = new LuaRover::LuaGlobal(lua_name);
				lua_states_.insert( std::make_pair( lua_name, lua_global ) );
			}
			else
			{
				lua_global = iter->second;
			}
		}

		return lua_global;
	}

	//////////////////////////////////////////////////////////////////////////
}